import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import { WristbandAdv } from '@entity/firmware/wristband_adv.entity';
import { WristbandAdvLast } from '@entity/firmware/wristband_adv_last.entity';
import { Wristband } from '@entity/firmware/wristband.entity';
// import { resBuild } from '@utils/resBuild';
import { GatewayWristband } from '@entity/firmware/gateway_wristband.entity';
import { v4 as uuidv4 } from 'uuid';
import { createClient } from 'redis';
import { resBuild } from '@utils/resBuild';

const redisClient = createClient();
redisClient.on('error', (err) => console.error('Redis Client Error', err));
redisClient.connect();
interface SleepData {
  sleep_duration: number; // 总睡眠时长（分钟）
  wake_up_time: string; // 起床时间
  bed_time: string; // 入睡时间
  deep_sleep_duration: number; // 深睡时长（分钟）
  light_sleep_duration: number; // 浅睡时长（分钟）
}
function calculateSleepData(result: any[]): SleepData {
  let sleepStart: Date | null = null;
  let wakeUpTime: Date | null = null;
  let totalSleep = 0;
  let deepSleep = 0;
  let lightSleep = 0;
  let lastState = 'awake';

  result.forEach((item) => {
    const { hr, acc_x, acc_y, acc_z, hrv, time } = item;

    // 确保日期有效
    const timestamp = new Date(time);
    if (isNaN(timestamp.getTime())) {
      // console.warn(`Invalid date: ${time}`);
      return; // 跳过无效日期的记录
    }

    const movement = Math.sqrt(acc_x ** 2 + acc_y ** 2 + acc_z ** 2);

    let currentState: 'awake' | 'light_sleep' | 'deep_sleep';

    if (hr < 50 && hrv > 40 && movement < 0.05) {
      currentState = 'deep_sleep';
    } else if (hr < 60 && movement < 0.2) {
      currentState = 'light_sleep';
    } else {
      currentState = 'awake';
    }

    if (currentState !== 'awake') {
      if (!sleepStart) sleepStart = timestamp;
      totalSleep += 1; // 假设数据是按 1 分钟间隔存储的
      if (currentState === 'deep_sleep') deepSleep += 1;
      if (currentState === 'light_sleep') lightSleep += 1;
    } else {
      if (lastState !== 'awake') {
        wakeUpTime = timestamp;
      }
    }

    lastState = currentState;
  });

  return {
    sleep_duration: totalSleep,
    wake_up_time: wakeUpTime ? wakeUpTime.toISOString() : '',
    deep_sleep_duration: deepSleep,
    light_sleep_duration: lightSleep,
    bed_time: sleepStart ? sleepStart.toISOString() : ''  // 添加 bed_time
  };
}


@Provide()
@Scope(ScopeEnum.Request, { allowDowngrade: true })
export class WristbandAdvService {
  @InjectEntityModel(WristbandAdv)
  wristbandAdvModel: Repository<WristbandAdv>;
  @InjectEntityModel(WristbandAdvLast)
  wristbandAdvLastModel: Repository<WristbandAdvLast>;
  @InjectEntityModel(Wristband)
  wristbandModel: Repository<Wristband>;

  @InjectEntityModel(GatewayWristband)
  gatewayWristbandModel: Repository<GatewayWristband>;


  // 删除 3天 之外的数据
  // 删除3天前的数据（带重试机制和分批删除）
  async deleteData() {
    try {
      const threeDaysAgo = new Date();
      threeDaysAgo.setDate(threeDaysAgo.getDate() - 3);
      //  打印 threeDaysAgo+ 8h
      console.log("开始删除3天前的数据（截至", new Date(threeDaysAgo.getTime() + 8 * 60 * 60 * 1000).toISOString().replace('T', ' ').replace('.000Z', ''), ")...");

      // 设置每批处理的时间范围（例如每次处理6小时数据）
      const BATCH_HOURS = 6;
      let currentEnd = new Date(threeDaysAgo);
      let currentStart = new Date(currentEnd);
      currentStart.setHours(currentEnd.getHours() - BATCH_HOURS);

      // 设置最早处理时间（防止无限回溯）
      const EARLIEST_DATE = new Date(0); // 1970-01-01
      let totalDeleted = 0;
      let hasMoreData = true;

      while (hasMoreData) {
        const deleteResult = await this.wristbandAdvModel.createQueryBuilder()
          .delete()
          .where('time BETWEEN :start AND :end', {
            start: currentStart,
            end: currentEnd
          })
          .execute();

        const deletedCount = deleteResult.affected || 0;
        totalDeleted += deletedCount;
        // // 测试用
        // console.log(
        //   `处理时间段: ${currentStart.toISOString()} 至 ${currentEnd.toISOString()}`,
        //   `删除 ${deletedCount} 条`
        // );

        // 移动时间窗口（无论是否有数据都继续）
        currentEnd = new Date(currentStart);
        currentStart.setHours(currentEnd.getHours() - BATCH_HOURS);

        // 检查是否到达最早时间
        if (currentStart <= EARLIEST_DATE) {
          console.log('已达到最早处理时间，停止删除');
          hasMoreData = false;
        }

        // 添加延迟减少锁竞争
        await new Promise(resolve => setTimeout(resolve, 100));
      }

      console.log('删除完成，总计删除', totalDeleted, '条数据');
      return resBuild.success(`清空三天前数据成功！共计删除 ${totalDeleted} 条`);
    } catch (err) {
      console.error('删除数据时出错:', err);
      return resBuild.fail('删除数据时出错');
    }
  }

  // mac是指 gw_mac
  // 获取所有数据接口
  async getAll(gw_mac: string): Promise<any> {
    try {
      // 1. 查找 gateway_wristband 表中的 wb_mac
      const gatewayWristband = await this.gatewayWristbandModel.findOne({
        where: { gw_mac: gw_mac }
      });

      if (!gatewayWristband) {
        // console.log('No associated gateway wristband found');
        return []; // 如果找不到相关记录
      }

      // 2. 将 wb_mac 字符串转为数组，确保没有空字符串
      const wb_mac_array = gatewayWristband.wb_mac.split(',').filter(Boolean);

      // 3. 初始化一个空数组用于存储查询结果
      const wb_mac_arrayData = [];

      // 4. 使用 for...of 遍历 wb_mac_array，查询每个 wb_mac 对应的 wristbandAdv 数据
      for (const wb_mac of wb_mac_array) {
        const wristbandAdvLastData = await this.wristbandAdvLastModel
          .createQueryBuilder('wristbandAdvLast')
          .leftJoinAndSelect('wristbandAdvLast.wristband', 'wristband')
          // .where('wristbandAdv.rssi > :rssi', { rssi: -90 })
          .where('wristbandAdvLast.rssi > :rssi', { rssi: -70 })
          .andWhere('wristbandAdvLast.gw_mac LIKE :gw_mac', { gw_mac: `%${gw_mac}%` })
          .andWhere('wristband.mac LIKE :wb_mac', { wb_mac:  `%${wb_mac}%` })  // 确保匹配 wb_mac
          .getOne();

        // 如果查询到数据，则添加到 wb_mac_arrayData
        if (wristbandAdvLastData) {
          wb_mac_arrayData.push(wristbandAdvLastData);
        }
      }

      // 5. 查询 wristbandAdv 表并且根据 rssi 和 gw_mac 做条件过滤
      const wristbandAdvLastData = await this.wristbandAdvLastModel
        .createQueryBuilder('wristbandAdvLast')
        .leftJoinAndSelect('wristbandAdvLast.wristband', 'wristband')
        .where('wristbandAdvLast.rssi > :rssi', { rssi: -90 })
        .andWhere('wristbandAdvLast.gw_mac LIKE :gw_mac', { gw_mac: `%${gw_mac}%` })
        .getMany();

      // 合并数据
      const mergedData = [...wb_mac_arrayData, ...wristbandAdvLastData];

      // 使用map根据mac去重
      const uniqueData = Array.from(
        new Map(mergedData.map(item => [item.wristband.mac, item])).values()
      );

      return {
        connected: gatewayWristband.wb_mac,  // 返回已经连接的 wb_mac 地址列表
        value: uniqueData         // 返回去重后的 wristbandAdv 数据
      };
    } catch (err) {
      // console.error('Error occurred:', err);
      return []; // 发生错误时返回空数组
    }
  }

  // 通过 手环 或 时间 查找 wristbandAdvModel 对应数据 date: 2025-3-11  wb_mac: xx:xx:xx:xx
  async getWbAll(queryParams): Promise<any> {
    const query = this.wristbandAdvModel.createQueryBuilder('wristband_adv');
    let { wb_mac, gw_mac, pageNum, pageSize } = queryParams;
    let date = [queryParams['date[0]'].replace("T", " ").replace(".000Z", ""), queryParams['date[1]'].replace("T", " ").replace(".000Z", "")]
    // 设置分页
    const skip = (pageNum - 1) * pageSize;  // 计算跳过的记录数
    const take = pageSize; // 设置每页返回的记录数
    console.log(11111, date, gw_mac, wb_mac, pageNum, pageSize)
    if (date) {
      query.andWhere('wristband_adv.time BETWEEN :start AND :end', {
        start: `${date[0]}`,
        end: `${date[1]}`,
      });
    }
    if (gw_mac) {
      query.andWhere('wristband_adv.gw_mac = :gw_mac', { gw_mac: gw_mac });
    }
    if (wb_mac) {
      query.andWhere('wristband_adv.mac = :mac', { mac: wb_mac });
    }
    // 添加分页到查询
    query.skip(skip).take(take);
    let result = await query.getMany() as any;
    // 计算睡眠数据
    const sleepStats = calculateSleepData(result);

    result.forEach((item) => {
      // 赋值计算出的睡眠数据
      item.sleep_duration = sleepStats.sleep_duration;
      item.wake_up_time = sleepStats.wake_up_time;
      item.bed_time = sleepStats.bed_time;
      item.deep_sleep_duration = sleepStats.deep_sleep_duration;
      item.light_sleep_duration = sleepStats.light_sleep_duration;
    });

    // 返回分页后的结果
    const total = await query.getCount(); // 获取总记录数
    console.log(2222, queryParams)
    return {
      data: result,
      total,  // 返回总记录数
      pageNum,  // 当前页码
      pageSize,  // 每页条数
    };
  }


  // 通过 网关 gw_mac 查找
  async getLastWbAll(params) {
    const { gw_mac } = params
    const query = this.wristbandAdvLastModel.createQueryBuilder('wristband_adv_last');
    if (gw_mac) {
      query.andWhere('wristband_adv_last.gw_mac = :gw_mac', { gw_mac: gw_mac });
    }

    const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000); // 当前时间减去5分钟
    console.log('5分钟前', fiveMinutesAgo)
    query.andWhere('wristband_adv_last.time >= :fiveMinutesAgo', { fiveMinutesAgo });
    // 按时间降序排列
    query.orderBy('wristband_adv_last.time', 'DESC');
    let result = await query.getMany() as any;
    // 计算睡眠数据
    const sleepStats = calculateSleepData(result);
    result.forEach((item) => {
      // 赋值计算出的睡眠数据
      item.sleep_duration = sleepStats.sleep_duration;
      item.wake_up_time = sleepStats.wake_up_time;
      item.bed_time = sleepStats.bed_time;
      item.deep_sleep_duration = sleepStats.deep_sleep_duration;
      item.light_sleep_duration = sleepStats.light_sleep_duration;
    });
    // 返回分页后的结果
    const total = await query.getCount(); // 获取总记录数
    return {
      data: result,
      total,  // 返回总记录数
    };
  }

  // 通过手环MAC查找 表对应的数据（有重复mac取最后一条数据）根据手环mac取实时数据的最后一条数据 查单个的时候
  /**
   * 获取手环的最后一条数据，支持分页和动态过滤
   * @param queryParams 查询参数，包含 mac、page 和 pageSize
   * @returns 分页后的记录和手环数量
   * SELECT  wa.* 
FROM wristband_adv wa
JOIN (
    SELECT MAX(wa1.id) AS id
    FROM wristband_adv wa1 
    GROUP BY wa1.mac 
    LIMIT 0, 10
) AS sub ON wa.id = sub.id;
   */
  // async getWbLast(queryParams: { wb_mac?: string; pageNum?: number; pageSize?: number }): Promise<any> {
  //   const { wb_mac, pageNum = 1, pageSize = 10 } = queryParams;

  //   // 生成缓存键
  //   const cacheKey = `wb_last:${wb_mac || 'all'}:${pageNum}:${pageSize}`;

  //   // 尝试从缓存中获取数据
  //   const cachedData = await redisClient.get(cacheKey);
  //   if (cachedData) {
  //       console.log('Returning data from cache');
  //       return JSON.parse(cachedData);
  //   }

  //   // 子查询：获取每个 mac 的 id 最大值
  //   const subQuery = this.wristbandAdvModel
  //     .createQueryBuilder('wa1')
  //     .select('MAX(wa1.id)', 'id') // 选择 id 字段
  //     .groupBy('wa1.mac'); // 按 mac 分组

  //   // 主查询：根据子查询的结果获取最新的记录
  //   let query = this.wristbandAdvModel
  //     .createQueryBuilder('wa')
  //     .select(['wa.*']) // 选择所有字段
  //     .innerJoin(
  //       `(${subQuery.getQuery()})`,
  //       'sub',
  //       'wa.id = sub.id'
  //     );

  //   // 如果有 wb_mac 参数，添加模糊查询条件
  //   if (wb_mac) {
  //     query = query.andWhere('wa.mac LIKE :mac', { mac: `%${wb_mac}%` });
  //   }

  //   // 获取总数
  //   const total = await query.getCount();

  //   // 分页逻辑
  //   const offset = (pageNum - 1) * pageSize;
  //   const result = await query
  //     .offset(offset) // 分页偏移量
  //     .limit(pageSize) // 限制返回记录数
  //     .getRawMany();

  //   // 构造返回结果
  //   const response = {
  //     data: result,
  //     total,
  //     pageNum,
  //     pageSize,
  //   };

  //   // 将结果缓存，设置过期时间为 5 分钟
  //   await redisClient.set(cacheKey, JSON.stringify(response), {
  //     EX: 300, // 过期时间（秒）
  //   });

  //   console.log('Data fetched from database and cached');
  //   return response;
  // }

  // 通过 mac 地址查找 wristband_adv_last 表中的数据
  async getWbLast(queryParams: { wb_mac?: string; gw_mac?:string; pageNum?: number; pageSize?: number }): Promise<any> {
    const { wb_mac, gw_mac, pageNum = 1, pageSize = 10 } = queryParams;

    // 创建查询构建器
    const query = this.wristbandAdvLastModel.createQueryBuilder('wristband_adv_last');

    // 如果 wb_mac 存在，进行大小写不敏感的模糊查询
    if (wb_mac) {
      // 将查询值和字段都转换为大写，除字母外的字符不受影响
      query.andWhere('UPPER(wristband_adv_last.mac) LIKE UPPER(:mac)', { mac: `%${wb_mac}%` });
    }
    if (gw_mac) {
      query.andWhere('UPPER(wristband_adv_last.gw_mac) LIKE UPPER(:gw_mac)', { gw_mac: `%${gw_mac}%` });
    }
    // 给时间 time 降序排序
    query.orderBy('wristband_adv_last.time', 'DESC');

    // 设置分页
    const skip = (pageNum - 1) * pageSize;  // 计算跳过的记录数
    const take = pageSize; // 设置每页返回的记录数
    query.skip(skip).take(take);

    // 获取总记录数
    const total = await query.getCount();

    // 获取分页数据
    const result = await query.getMany();

    return {
      data: result,
      total,  // 返回总记录数
      pageNum,  // 当前页码
      pageSize,  // 每页条数
    };
  }





  // 上海来捞的数据
  async getWbData(queryParams): Promise<any> {
    const query = this.wristbandAdvModel.createQueryBuilder('wristband_adv');
    let date = queryParams.date;
    let wb_mac = queryParams.wb_mac;

    if (date) {
      query.andWhere('wristband_adv.time BETWEEN :start AND :end', {
        start: `${date} 00:00:00`,
        end: `${date} 23:59:59`,
      });
    }

    if (wb_mac) {
      query.andWhere('wristband_adv.mac = :wb_mac', { wb_mac });
    }

    let result = await query.getMany();
    // 计算睡眠数据
    const sleepStats = calculateSleepData(result);

    // 按日期整理数据
    const formattedResult = result.reduce((acc, item) => {
      const dateKey = new Date(item.time).toISOString().split('T')[0]; // 提取日期部分
      // 通过日期来聚合，保留所有 mac
      if (!acc[dateKey]) {
        acc[dateKey] = []; // 每个日期对应一个记录数组
      }
      // 将每一条记录添加到对应日期的数组中
      acc[dateKey].push({
        date: dateKey,
        mac: item.mac,
        steps: item.steps, // 假设在 result 中有 steps 字段
        sleep_duration: sleepStats.sleep_duration,
        wake_up_time: sleepStats.wake_up_time,
        bed_time: sleepStats.bed_time,
        deep_sleep_duration: sleepStats.deep_sleep_duration,
        light_sleep_duration: sleepStats.light_sleep_duration,
      });

      return acc;
    }, {});
    // 将最终结果转换为数组，并按 mac 和 time 排序
    const flattenedResult = Object.values(formattedResult).flat() as any;
    flattenedResult.sort((a, b) => {
      // 按 mac 排序（字典顺序）
      if (a.mac < b.mac) return -1;
      if (a.mac > b.mac) return 1;

      // 如果 mac 相同，则按时间排序（升序）
      return new Date(a.date) > new Date(b.date) ? 1 : -1;
    });

    return flattenedResult;
  }






  // 绑定接口
  async setGatewayWristband(params) {
    // console.log('body', params);
    try {
      // 1. Convert wb_mac array to a comma-separated string
      const wb_mac_str = params.wb_mac.filter(Boolean).join(','); // Filter out any empty strings before joining
      // console.log(uuidv4());

      // 2. Check if the gw_mac already exists
      let existingRecord = await this.gatewayWristbandModel.findOne({
        where: { gw_mac: params.gw_mac },
      });

      if (existingRecord) {
        // 3. If record exists, update the wb_mac field
        existingRecord.wb_mac = wb_mac_str; // Set the new wb_mac value
        existingRecord.deleted = 0; // Ensure 'deleted' is set correctly

        // 4. Save the updated record
        const updatedRecord = await this.gatewayWristbandModel.save(existingRecord);
        // console.log('Updated gateway_wristband:', updatedRecord);
        return updatedRecord;
      } else {
        // 5. If record does not exist, insert a new one
        const data = {
          id: uuidv4(),          // Ensure id is being passed
          gw_mac: params.gw_mac, // Ensure gw_mac is passed properly
          wb_mac: wb_mac_str,    // Store the comma-separated string
          deleted: 0,            // Explicitly pass deleted value
        };

        const result = await this.gatewayWristbandModel.save(data);
        // console.log('Saved gateway_wristband:', result);
        return result;
      }
    } catch (err) {
      // console.error('Error occurred while saving to gateway_wristband:', err);
      throw new Error('Failed to save data');
    }
  }



  // 解绑接口
  async unsetGatewayWristband(params) {
    console.log('body', params);
    try {
      // 1. 根据给定的 gw_mac 查找是否存在相关记录
      let existingRecord = await this.gatewayWristbandModel.findOne({
        where: { gw_mac: params.gw_mac },
      });

      if (!existingRecord) {
        console.log('未找到对应的 gw_mac 记录:', params.gw_mac);
        throw new Error('未找到相关记录'); // 没有找到记录
      }

      // 2. 将数据库中存储的 wb_mac 字符串转为数组
      const existingWbMacArray = existingRecord.wb_mac.split(',');

      // 3. 检查要解绑的 wb_mac 是否存在于当前记录中
      if (!existingWbMacArray.includes(params.wb_mac)) {
        console.log('wb_mac 未在该 gw_mac 记录中找到');
        throw new Error('wb_mac 未在该 gw_mac 记录中找到');  // 要解绑的 wb_mac 不在该记录中
      }

      // 4. 从现有数组中移除指定的 wb_mac
      const updatedWbMacArray = existingWbMacArray.filter(
        (mac) => mac !== params.wb_mac
      );

      // 5. 如果解绑后没有剩余的 wb_mac，可以选择删除记录或将其标记为已删除
      if (updatedWbMacArray.length === 0) {
        existingRecord.deleted = 1; // 标记为已删除（你可以选择直接删除记录）
        existingRecord.wb_mac = ''; // 清空 wb_mac 字段（设置为空字符串）

        // 保存更新后的记录（标记为已删除）
        const updatedRecord = await this.gatewayWristbandModel.save(existingRecord);
        console.log('解绑并标记为已删除:', updatedRecord);
        return updatedRecord;
      } else {
        // 6. 如果仍然有 wb_mac，更新 wb_mac 字段
        existingRecord.wb_mac = updatedWbMacArray.join(','); // 将数组转换回逗号分隔的字符串

        // 保存更新后的记录
        const updatedRecord = await this.gatewayWristbandModel.save(existingRecord);
        console.log('解绑 wb_mac:', updatedRecord);
        return updatedRecord;
      }
    } catch (err) {
      console.error('解绑过程中出错:', err);
      throw new Error('解绑数据失败');
    }
  }


  async getByMac(mac: string): Promise<WristbandAdv[]> {
    return this.wristbandAdvModel.find({ where: { mac } });
  }

  // 保存手环广播数据
  async createAdv(
    gw_mac: string,
    mac: string,
    rssi: number,
    data: Partial<WristbandAdv>,
    format: number,
    date
  ): Promise<WristbandAdv> {
    try {
      // 检查 wristband 是否存在
      const existingWristband = await this.wristbandModel.findOne({ where: { mac } });
      if (!existingWristband) {
        // 使用 save 方法插入或更新记录
        await this.wristbandModel
          .createQueryBuilder()
          .insert()
          .into(Wristband)
          .values({
            id: uuidv4(),
            mac,
            // time: date,
            time: new Date()
          })
          .orIgnore() // 如果 mac 地址已存在则忽略
          .execute();
        // console.log(`Wristband checked/added with MAC: ${mac}`);
      } else {
        // console.log(`Wristband with MAC: ${mac} already exists.`);
      }

      // 插入 wristbandAdv（无条件新增）
      const newWristbandAdv = this.wristbandAdvModel.create({
        gw_mac,
        mac,
        rssi,
        ...data,
        // time: date,
        time: new Date(),
        format
      });

      const savedRecord = await this.wristbandAdvModel.save(newWristbandAdv);
      // console.log(`WristbandAdv added with ID: ${savedRecord.id}`);
      return savedRecord;
    } catch (err) {
      console.error('Error occurred while creating wristbandAdv:', err);
      // throw new Error('Failed to create wristbandAdv record');
    }
  }

  // 保存手环最终广播数据 saveLastAdv
  async saveLastAdv(
    gw_mac: string,
    mac: string,
    rssi: number,
    data: Partial<WristbandAdv>,
    format: number,
    date: Date
  ): Promise<WristbandAdvLast> {
    try {
      // 检查 wristband 是否存在，如果不存在则插入
      await this.ensureWristbandExists(mac);

      // 准备 wristbandAdvLast 的数据
      const wristbandAdvLastData = {
        gw_mac,
        mac,
        rssi,
        format,
        time: new Date(),
        ...data
      };

      // 使用 upsert 方法插入或更新记录
      const savedRecord = await this.wristbandAdvLastModel.upsert(wristbandAdvLastData, ['mac']);
      return savedRecord.generatedMaps[0] as WristbandAdvLast;
    } catch (err) {
      console.error('Error occurred while creating wristbandAdvLast:', err);
      throw new Error('Failed to create wristbandAdvLast record');
    }
  }

  private async ensureWristbandExists(mac: string): Promise<void> {
    const existingWristband = await this.wristbandModel.findOne({ where: { mac } });
    if (!existingWristband) {
      await this.wristbandModel
        .createQueryBuilder()
        .insert()
        .into(Wristband)
        .values({
          id: uuidv4(),
          mac,
          time: new Date(),
        })
        .orIgnore() // 如果 mac 地址已存在则忽略
        .execute();
    }
  }


}